﻿using log4net;
using System;
using System.Collections;
using System.Reflection;

namespace Velocity4Net.Runtime.Parser.Node
{

    /*
     * Licensed to the Apache Software Foundation (ASF) under one
     * or more contributor license agreements.  See the NOTICE file
     * distributed with this work for additional information
     * regarding copyright ownership.  The ASF licenses this file
     * to you under the Apache License, Version 2.0 (the
     * "License"); you may not use this file except in compliance
     * with the License.  You may obtain a copy of the License at
     *
     *   http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing,
     * software distributed under the License is distributed on an
     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     * KIND, either express or implied.  See the License for the
     * specific language governing permissions and limitations
     * under the License.
     */






    /**
     * GetExecutor that is smart about Maps. If it detects one, it does not
     * use Reflection but a cast to access the getter.
     *
     * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
     * @version $Id: MapGetExecutor.java 1780734 2017-01-28 19:21:08Z cbrisson $
     * @since 1.5
     */
    public class MapGetExecutor : AbstractExecutor
    {
        private readonly String property;
        private readonly bool isAlive;

        public MapGetExecutor(ILog log, Object _object, String property)
        {
            this.log = log;
            this.property = property;
            isAlive = discover(_object);
        }


        public override MethodInfo getMethod()
        {
            if (isAlive())
            {
                return MapGetMethod.instance();
            }
            return null;
        }


        public override bool isAlive()
        {
            return isAlive;
        }

        protected bool discover(Object _object)
        {
            if (object is Map)
            {
                if (property != null)
                {
                    return true;
                }
            }
            return false;
        }

        public Object execute(Object o)
        {
            return ((Map)o).get(property);
        }

        private class MapGetMethod
        {
            private const MethodInfo instance;

            static MapGetMethod()
            {
                try
                {
                    instance = typeof(IDictionary).getMethod("get", typeof(Object));
                }
                catch (NotSupportedException mapGetMethodMissingError)
                {
                    throw new Exception(mapGetMethodMissingError);
                }
            }

            private MapGetMethod() { }

            static MethodInfo instance()
            {
                return instance;
            }
        }
    }
}